feat: expose query operation timings#2491
Conversation
WalkthroughAdds an OperationTimings struct and Timings() methods to expose parsing, validation, planning, and normalization durations; introduces a router middleware module that captures those timings and sends them over a channel; and adds tests that run queries and assert timing fields are non-negative and at least one is non-zero. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@router-tests/modules/custom-operation-timings/module.go`:
- Around line 16-23: The middleware OperationTimingsModule.Middleware currently
does a blocking send m.ResultsChan <- timings which can hang when ResultsChan is
nil or unbuffered; update Middleware to first check if m.ResultsChan != nil and
then perform a non-blocking send using a select with a default case so the
request path never stalls (i.e., attempt to send timings on m.ResultsChan in one
select case and use default to skip sending if it would block), leaving the rest
of the handler flow (next.ServeHTTP(ctx.ResponseWriter(), ctx.Request()))
unchanged.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@router-tests/modules/custom-operation-timings/module.go`:
- Around line 31-41: The ResultsChan is created unbuffered in
OperationTimingsModule.Module() so non-blocking sends can drop timings; change
the New function to initialize ResultsChan as a buffered channel (e.g.,
make(chan core.OperationTimings, 1)) inside the New closure that returns
&OperationTimingsModule to preserve the latest timing without blocking callers.
|
Hi, thanks for your contribution. Could you also add a PR description with your use case. We usually have descriptions on the PRs in addition to what is generated by coderabbit. |
|
@SkArchon Sorry I should have added it right away! Updated the description, please let me know what do you think? |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2491 +/- ##
==========================================
- Coverage 62.45% 56.05% -6.41%
==========================================
Files 231 215 -16
Lines 24123 23548 -575
==========================================
- Hits 15066 13199 -1867
- Misses 7809 9107 +1298
+ Partials 1248 1242 -6
🚀 New features to boost your workflow:
|
|
HI @AlenaSviridenko, please also create PR to document that functionality https://github.com/wundergraph/cosmo-docs/blob/main/docs/router/custom-modules.mdx Thank you! |
Co-authored-by: Alessandro Pagnin <ale@wundergraph.com>
Corresponding docs PR wundergraph/cosmo-docs#248
Why this change is needed
Our app uses a custom Go module to publish detailed per-request telemetry to our internal Hydro system (Kafka-based). We need GraphQL operation performance metrics (parse, normalize, validate, plan timing) for every request to analyze query performance and debug issues.
While we already export OTEL metrics to Datadog, we need the raw per-request timing data in our telemetry pipeline. Currently, these timings are only accessible by passing the
X-WG-Traceheader, which has several problems:This PR exposes operation timings via the
OperationContextinterface (similar to the existingQueryPlanStats()method), allowing custom modules to access this data programmatically without modifying responses or requiring client headers.This enables us to:
Summary by CodeRabbit
New Features
Tests
Checklist